#include <xmlparser.h>
#include <iostream>
#include "math.h"
#include "model.h"


XMLParser::XMLParser()
{

    // makeCurrent();
    textureIDs = new GLuint[10];
    minx=-1000;
    miny=-1000;
    minz=-1000;
    maxx=1000;
    maxy=1000;
    maxz=1000;
}

void XMLParser::parse()
{
    QString filename(":/data/building.xml");
    int errorLine, errorColumn;
    QString errorMsg;
    QFile modelFile(filename);
    QDomDocument document;
    if(!document.setContent(&modelFile,&errorMsg,&errorLine,&errorColumn))
    {
        QString error("gebt nen error dommerik!!!!");
        std::cout<< error.toStdString()+"\n";
        //return false;
    }

    QDomElement rootElement=document.documentElement();


    for(QDomNode node =rootElement.firstChild();!node.isNull();node=node.nextSibling())
    {


        if(node.toElement().tagName()=="variables")
        {

            setVariables(node);

        }
        if(node.toElement().tagName()=="properties")
        {

            setProperties(node);

        }
        if(node.toElement().tagName()=="objects")
        {

            object=makeObjects(node);

            std::cout <<"done\n";

        }

        if(node.toElement().tagName()=="onclick")
        {
            onclicks(node);
        }
    }
}

GLuint XMLParser::getObject()
{
    return object;
}
GLuint XMLParser::makeObjects(QDomNode n)
{
    QDomElement element=n.firstChild().toElement();
    QVector<GLuint> v;
    while(!element.isNull())
    {
        if(element.tagName()=="object")
        {
            GLfloat x=element.attribute("startX").toFloat();
            GLfloat y=element.attribute("startY").toFloat();
            GLfloat z=element.attribute("startZ").toFloat();

            std::cout<< y<< "\n";

            GLuint list1;
            list1=glGenLists(1);
            glNewList(list1,GL_COMPILE);


            glCallList( makeObject(element,x,y,z));



            glEndList();

            v.append(list1);
        }
        element=element.nextSibling().toElement();
    }

    int i=-1;
    GLuint list;
    list=glGenLists(1);


    glNewList(list,GL_COMPILE);

    do
    {
        if(glIsList(v.value(i+1)))
        {
            std::cout << "ok "<<std::endl;
        }
        glCallList(v.value(i+1));
        i++;
    } while(v.value(i)!=v.last());

    glEndList();

    return list;
}
GLuint XMLParser::makeObject(QDomElement e, GLfloat x, GLfloat y, GLfloat z)
{

    if(e.attribute("type")=="quad")
    {
        GLuint list;
        list=glGenLists(1);
        glNewList(list,GL_COMPILE);
        glPushMatrix();
        ids.insert(ids.size(),e.attribute("id"));
        glPushName(ids.size()-1);
        glTranslatef(x,y,z);
        drawQuad(e);
        glPopName();
        glPopMatrix();
        glEndList();
        return list;
    }
    else if(e.attribute("type")=="cube")
    {
        GLuint list;
        list=glGenLists(1);
        glNewList(list,GL_COMPILE);
        glPushMatrix();
        ids.insert(ids.size(),e.attribute("id"));
        glPushName(ids.size()-1);
        glTranslatef(x,y,z);
        drawCube(e);
        glPopName();
        glPopMatrix();
        glEndList();
        return list;
    }
    else if(e.attribute("type")=="ref")
    {

        GLuint list;
        list=glGenLists(1);
        glNewList(list,GL_COMPILE);
        glPushMatrix();  ids.insert(ids.size(),e.attribute("id"));
        glPushName(ids.size()-1);

        glTranslatef(x,y,z);
        glCallList( lists.value(e.attribute("ref")));
        glTranslatef(-x,-y,-z);
        glPopName();
        glPopMatrix();
        glEndList();
        return list;
    }
    else if(e.attribute("type")=="obj"){
        std::cout<<"obj";
        GLuint list;
        list=glGenLists(1);
        glNewList(list,GL_COMPILE);
        glPushMatrix();
        ids.insert(ids.size(),e.attribute("id"));
        glPushName(ids.size()-1);
        glTranslatef(x,y,z);
        Model *model = new Model(e.attribute("file"));
        LoadGLTextures(e.attribute("texture"));
        model->draw();

        glTranslatef(-x,-y,-z);
        glPopName();
        glPopMatrix();
        glEndList();
        return list;

    }
    return 1;
}


void XMLParser::drawCube(QDomElement e)
{


    LoadGLTextures(e.attribute("texture"));
    glEnable(GL_TEXTURE_2D);


    glBegin(GL_QUADS);
    GLfloat fac=0.2f;
    QDomElement element=e.firstChild().toElement();
    GLfloat width=element.attribute("width").toFloat();

    GLfloat height=element.attribute("height").toFloat();
    GLfloat depth=element.attribute("depth").toFloat();
    GLfloat widthTex=width*fac;
    GLfloat heightTex=height*fac;
    GLfloat depthTex=depth*fac;


    glNormal3f(0.0,0.0,-1.0);glTexCoord2f(0.0f, 0.0f); glVertex3f(0, 0,  -depth);
    glNormal3f(0.0,0.0,-1.0);glTexCoord2f(widthTex, 0.0f); glVertex3f( width, 0,  -depth);
    glNormal3f(0.0,0.0,-1.0);glTexCoord2f(widthTex, heightTex); glVertex3f( width,height, -depth);
    glNormal3f(0.0,0.0,-1.0);glTexCoord2f(0.0f, heightTex); glVertex3f(0, height,  -depth);

    glNormal3f(0.0,0.0,1.0);glTexCoord2f(widthTex, 0.0f); glVertex3f(0, 0, 0.0f);
    glNormal3f(0.0,0.0,1.0);glTexCoord2f(widthTex, heightTex); glVertex3f(0,  height, 0.0f);
    glNormal3f(0.0,0.0,1.0);glTexCoord2f(0.0f, heightTex); glVertex3f( width, height, 0.0f);
    glNormal3f(0.0,0.0,1.0);glTexCoord2f(0.0f, 0.0f); glVertex3f( width, 0, 0.0f);


    glNormal3f(0.0,1.0,0.0);glTexCoord2f(0.0f, depthTex); glVertex3f(0,  height, 0);
    glNormal3f(0.0,1.0,0.0);glTexCoord2f(0.0f, 0.0f); glVertex3f(0,  height,  -depth);
    glNormal3f(0.0,1.0,0.0);glTexCoord2f(widthTex, 0.0f); glVertex3f( width,  height,  -depth);
    glNormal3f(0.0,1.0,0.0); glTexCoord2f(widthTex, heightTex); glVertex3f( width,  height, 0);

    glNormal3f(0.0,-1.0,0.0);glTexCoord2f(widthTex, depthTex); glVertex3f(0, 0.0f,0);
    glNormal3f(0.0,-1.0,0.0);glTexCoord2f(0.0f, depthTex); glVertex3f(width, 0.0f, 0);
    glNormal3f(0.0,-1.0,0.0);glTexCoord2f(0.0f, 0.0f); glVertex3f( width, 0.0f,  -depth);
    glNormal3f(0.0,-1.0,0.0);glTexCoord2f(widthTex, 0.0f); glVertex3f(0, 0.0f,  -depth);


    glNormal3f(1.0,0.0,0.0);glTexCoord2f( 0.0f,depthTex); glVertex3f( width, 0, 0);
    glNormal3f(1.0,0.0,0.0);glTexCoord2f(heightTex,depthTex); glVertex3f( width,  height,0);
    glNormal3f(1.0,0.0,0.0);glTexCoord2f(heightTex,0.0f); glVertex3f(width,  height, -depth);
    glNormal3f(1.0,0.0,0.0);glTexCoord2f(0.0f, 0.0f); glVertex3f( width, 0,  -depth);


    glNormal3f(-1.0,0.0,0.0);glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 0, 0);
    glNormal3f(-1.0,0.0,0.0);glTexCoord2f(depthTex, 0.0f); glVertex3f(0.0f, 0, -depth);
    glNormal3f(-1.0,0.0,0.0);glTexCoord2f(depthTex, heightTex); glVertex3f(0.0f,  height,  -depth);
    glNormal3f(-1.0,0.0,0.0);glTexCoord2f(0.0f,heightTex); glVertex3f(0.0f,  height, 0);
    //    for(int i=0;i<width/fac;i++)
    //    {
    //        for(int j=0;j<height/fac;j++){


    //            glNormal3f(0.0,0.0,-1.0);glTexCoord2f(0.0f, 0.0f); glVertex3f(i*fac, j*fac,  -depth);
    //            glNormal3f(0.0,0.0,-1.0);glTexCoord2f(1, 0.0f); glVertex3f( (i+1)*fac, j*fac,  -depth);
    //            glNormal3f(0.0,0.0,-1.0);glTexCoord2f(1, 1); glVertex3f( (i+1)*fac, (j+1)*fac, -depth);
    //            glNormal3f(0.0,0.0,-1.0);glTexCoord2f(0.0f, 1); glVertex3f(i*fac, (j+1)*fac,  -depth);
    //        }
    //    }
    //    // Back Face



    //    for(int i=0;i<width/fac;i++)
    //    {
    //        for(int j=0;j<height/fac;j++){


    //            glNormal3f(0.0,0.0,1.0);glTexCoord2f(1, 0.0f); glVertex3f(i*fac, j*fac, 0.0f);
    //            glNormal3f(0.0,0.0,1.0);glTexCoord2f(1, 1); glVertex3f(i*fac,  (j+1)*fac, 0.0f);
    //            glNormal3f(0.0,0.0,1.0);glTexCoord2f(0.0f, 1); glVertex3f( (i+1)*fac, (j+1)*fac, 0.0f);
    //            glNormal3f(0.0,0.0,1.0);glTexCoord2f(0.0f, 0.0f); glVertex3f( (i+1)*fac, j*fac, 0.0f);
    //        }
    //    }
    //    // Top Face

    //    for(int i=0;i<width/fac;i++)
    //    {
    //        for(int j=0;j<depth/fac;j++){


    //            glNormal3f(0.0,1.0,0.0);glTexCoord2f(0.0f, 1); glVertex3f(i*fac,  height, -j*fac);
    //            glNormal3f(0.0,1.0,0.0);glTexCoord2f(0.0f, 0.0f); glVertex3f(i*fac,  height,  -(j+1)*fac);
    //            glNormal3f(0.0,1.0,0.0);glTexCoord2f(1, 0.0f); glVertex3f( (i+1)*fac,  height,  -(j+1)*fac);
    //            glNormal3f(0.0,1.0,0.0); glTexCoord2f(1, 1); glVertex3f( (i+1)*fac,  height, -j*fac);
    //        }
    //    }
    //    // Bottom Face


    //    for(int i=0;i<width/fac;i++)
    //    {
    //        for(int j=0;j<depth/fac;j++){



    //            glNormal3f(0.0,-1.0,0.0);glTexCoord2f(1, 1); glVertex3f(i*fac, 0.0f,-j*fac);
    //            glNormal3f(0.0,-1.0,0.0);glTexCoord2f(0.0f, 1); glVertex3f((i+1)*fac, 0.0f, -j*fac);
    //            glNormal3f(0.0,-1.0,0.0);glTexCoord2f(0.0f, 0.0f); glVertex3f( (i+1)*fac, 0.0f,  -(j+1)*fac);
    //            glNormal3f(0.0,-1.0,0.0);glTexCoord2f(1, 0.0f); glVertex3f(i*fac, 0.0f,  -(j+1)*fac);
    //        }}
    //    // Right face
    //    for(int i=0;i<height/fac;i++)
    //    {
    //        for(int j=0;j<depth/fac;j++){




    //            glNormal3f(1.0,0.0,0.0);glTexCoord2f(1, 0.0f); glVertex3f( width, i*fac, -j*fac);
    //            glNormal3f(1.0,0.0,0.0);glTexCoord2f(1, 1); glVertex3f( width,  (i+1)*fac,- j*fac);
    //            glNormal3f(1.0,0.0,0.0);glTexCoord2f(0.0f, 1); glVertex3f(width,  (i+1)*fac, -(j+1)*fac);
    //            glNormal3f(1.0,0.0,0.0);glTexCoord2f(0.0f, 0.0f); glVertex3f( width, i*fac,  -(j+1)*fac);
    //        }}
    //    // Left Face
    //    for(int i=0;i<height/fac;i++)
    //    {
    //        for(int j=0;j<depth/fac;j++){




    //            glNormal3f(-1.0,0.0,0.0);glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, i*fac, -j*fac);
    //            glNormal3f(-1.0,0.0,0.0);glTexCoord2f(depthTex, 0.0f); glVertex3f(0.0f, i*fac, -(j+1)*fac);
    //            glNormal3f(-1.0,0.0,0.0);glTexCoord2f(depthTex, heightTex); glVertex3f(0.0f,  (i+1)*fac,  -(j+1)*fac);
    //            glNormal3f(-1.0,0.0,0.0);glTexCoord2f(0.0f,heightTex); glVertex3f(0.0f,  (i+1)*fac, -j*fac);
    //        }}



    glEnd(); // Done Drawing The Quad







}
void XMLParser::LoadGLTextures(QString fileName)
{
    QString filePath(":/data/");
    filePath.append(fileName);

    QImage t;
    QImage b;

    if ( !b.load(filePath.toLatin1().data()))
    {
        b = QImage();
        b.fill(Qt::white);
    }

    t = QGLWidget::convertToGLFormat( b );

    glGenTextures( 10, textureIDs);
    glBindTexture ( GL_TEXTURE_2D, textureIDs[0]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D( GL_TEXTURE_2D, 0, 3, t.width(), t.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, t.bits() );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
}

void XMLParser::drawQuad(QDomElement e)
{
    GLfloat scaleX=e.attribute("scaleX").toFloat();
    GLfloat scaleY=e.attribute("scaleY").toFloat();
    LoadGLTextures(e.attribute("texture"));
    glEnable(GL_TEXTURE_2D);

    GLfloat nx=e.attribute("normalX").toFloat();
    GLfloat ny=e.attribute("normalY").toFloat();
    GLfloat nz=e.attribute("normalZ").toFloat();
    QDomElement element=e.firstChild().toElement();
    GLfloat* p1=getPoint(element);
    element=element.nextSibling().toElement();
    GLfloat* p2=getPoint(element);
    element=element.nextSibling().toElement();
    GLfloat* p3=getPoint(element);
    element=element.nextSibling().toElement();
    GLfloat* p4=getPoint(element);


    //    GLfloat width=sqrt(pow(p1[0]-p2[0],2)+pow(p1[1]-p2[1],2)+pow(p1[2]-p2[2],2))*5;
    //    GLfloat difwidth[]={-(p1[0]-p2[0])/width,-(p1[1]-p2[1])/width,-(p1[2]-p2[2])/width};


    //    GLfloat lenght=sqrt(pow(p1[0]-p4[0],2)+pow(p1[1]-p4[1],2)+pow(p1[2]-p4[2],2))*5;
    //    GLfloat diflength[]={-(p1[0]-p4[0])/lenght,-(p1[1]-p4[1])/lenght,-(p1[2]-p4[2])/lenght};

    //    std::cout<<lenght<<"<<"<<width<<"\n";
    glBegin(GL_QUADS);
    //    for(int x=0;x<width;x++)
    //    {

    //        for (int y=0;y<lenght;y++)
    //        {


    //            glNormal3f(nx,ny,nz);
    //            glTexCoord2d(scaleX, 0);
    //            glVertex3f(p1[0]+difwidth[0]*x+diflength[0]*y,p1[1]+difwidth[1]*x+diflength[1]*y,p1[2]+difwidth[2]*x+diflength[2]*y);


    //            glNormal3f(nx,ny,nz);
    //            glTexCoord2d(scaleX, scaleY);
    //            glVertex3f(p1[0]+difwidth[0]*(x+1)+diflength[0]*y,p1[1]+difwidth[1]*(x+1)+diflength[1]*y,p1[2]+difwidth[2]*(x+1)+diflength[2]*y);


    //            glNormal3f(nx,ny,nz);
    //            glTexCoord2d(0, scaleY);
    //            glVertex3f(p1[0]+difwidth[0]*(x+1)+diflength[0]*(y+1),p1[1]+difwidth[1]*(x+1)+diflength[1]*(y+1),p1[2]+difwidth[2]*(x+1)+diflength[2]*(y+1));

    //            glNormal3f(nx,ny,nz);
    //            glTexCoord2d(0, 0);
    //            glVertex3f(p1[0]+difwidth[0]*(x)+diflength[0]*(y+1),p1[1]+difwidth[1]*(x)+diflength[1]*(y+1),p1[2]+difwidth[2]*(x)+diflength[2]*(y+1));




    //        }
    //    }

    glNormal3f(nx,ny,nz);
    glTexCoord2d(scaleX, 0);
    glVertex3fv(p1);



    glTexCoord2d(scaleX, scaleY);
    glVertex3fv(p2);



    glTexCoord2d(0, scaleY);
    glVertex3fv(p3);

    glTexCoord2d(0, 0);
    glVertex3fv(p4);


    glEnd();


}

GLfloat* XMLParser::getPoint(QDomElement e)
{


    if(e.attribute("ref")!="none")
    {
        GLfloat* f=new GLfloat;
        QVector<GLfloat> v=points.find(e.attribute("ref")).value();
        for(int i=0;i<3;i++)
        {
            f[i]=v.value(i);

        }


        return f;
    }
    else
    {
        return NULL;
    }
}

void XMLParser::setVariables(QDomNode n)
{

    QDomNode node=n.firstChild();
    while(!node.isNull()){
        if(node.toElement().tagName()=="points")
        {
            for(QDomElement child =node.firstChild().toElement();!child.isNull();child=child.nextSibling().toElement())
            {
                if(child.toElement().tagName()=="point")
                {
                    QVector<GLfloat> vector;
                    vector.append(child.attribute("x").toFloat());
                    vector.append(child.attribute("y").toFloat());
                    vector.append(child.attribute("z").toFloat());

                    points[child.attribute("id")]=vector;

                }
            }
        }
        else if(node.toElement().tagName()=="list")
        {
            GLuint list;
            list=glGenLists(1);

            glNewList(list,GL_COMPILE);


            for(QDomElement child =node.firstChild().toElement();!child.isNull();child=child.nextSibling().toElement())
            {
                if(child.toElement().tagName()=="item")
                {

                    glCallList( makeObject(child.toElement()));

                }
            }
            glEndList();
            lists[node.toElement().attribute("id")]=list;
        }
        node=node.nextSibling();
    }

}

void XMLParser::onclicks(QDomNode n)
{
    QDomElement element=n.firstChild().toElement();
    while(!element.isNull())
    {
        GLuint list=makeObject(element,element.attribute("startX").toFloat(),element.attribute("startY").toFloat(),element.attribute("startZ").toFloat());
        onclick.insert(element.attribute("id"),list);
        element=element.nextSibling().toElement();
    }
}

void XMLParser::setProperties(QDomNode n)
{
    QDomNode node=n.firstChild();
    while(!node.isNull()){
        if(node.toElement().tagName()=="camera")
        {
            QDomElement element=node.firstChild().toElement();
            if(element.tagName()=="position")
            {
                startx=element.attribute("x").toFloat();
                starty=element.attribute("y").toFloat();
                startz=element.attribute("z").toFloat();
                minx=element.attribute("minX").toFloat();
                miny=element.attribute("minY").toFloat();
                minz=element.attribute("minZ").toFloat();
                maxx=element.attribute("maxX").toFloat();
                maxy=element.attribute("maxY").toFloat();
                maxz=element.attribute("maxZ").toFloat();
            }
        }
        else if(node.toElement().tagName()=="lights")
        {
            QDomElement light= node.firstChild().toElement();
            int i=0;
            lights=glGenLists(1);
            glNewList(lights,GL_COMPILE);

            while(!light.isNull()){

                float ambient[]   = {0.8f, 0.8f, 0.8f,1.0f};
                glLightfv(GL_LIGHT1+i, GL_AMBIENT,ambient);
                float difuse[]   = {1.0f, 1.0f, 1.0f,1.0f};
                glLightfv(GL_LIGHT1+i, GL_DIFFUSE,difuse);
                GLfloat specular[] = {1.0f, 1.0f, 1.0f , 1.0f};
                glLightfv(GL_LIGHT1+i, GL_SPECULAR, specular);



                GLfloat e[]={light.firstChild().toElement().attribute("x").toFloat(),light.firstChild().toElement().attribute("y").toFloat(),light.firstChild().toElement().attribute("z").toFloat(),1.0f};
                glLightfv(GL_LIGHT1+i,GL_POSITION,e);

                GLfloat dir[]={0,-70.0,0,1.0};
                glLightfv(GL_LIGHT1+i,GL_SPOT_DIRECTION,dir);
                glLightf(GL_LIGHT1+i,GL_SPOT_CUTOFF,90);
                glLightf(GL_LIGHT1+i,GL_SPOT_EXPONENT,30);
                light=light.nextSibling().toElement();
                i++;
            }
            glEndList();
        }
        node=node.nextSibling();
    }
}


